From: Keir Fraser Date: Thu, 17 Apr 2008 11:37:35 +0000 (+0100) Subject: x86, hvm: Allow emulation of 'multi-cycle' MMIO reads and writes, X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14215^2~165 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=29a3d669c7a4d4f504bbaeb911133e20d6971d85;p=xen.git x86, hvm: Allow emulation of 'multi-cycle' MMIO reads and writes, which may require multiple round trips to the device model. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 093bf571d9..112e8094ec 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -28,6 +28,33 @@ static int hvmemul_do_io( ioreq_t *p = &vio->vp_ioreq; int rc; + /* Only retrieve the value from singleton (non-REP) reads. */ + ASSERT((val == NULL) || ((dir == IOREQ_READ) && !value_is_ptr)); + + if ( is_mmio && !value_is_ptr ) + { + /* Part of a multi-cycle read or write? */ + if ( dir == IOREQ_WRITE ) + { + paddr_t pa = curr->arch.hvm_vcpu.mmio_large_write_pa; + unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_write_bytes; + if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) ) + return X86EMUL_OKAY; + } + else + { + paddr_t pa = curr->arch.hvm_vcpu.mmio_large_read_pa; + unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_read_bytes; + if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) ) + { + *val = 0; + memcpy(val, &curr->arch.hvm_vcpu.mmio_large_read[addr - pa], + size); + return X86EMUL_OKAY; + } + } + } + switch ( curr->arch.hvm_vcpu.io_state ) { case HVMIO_none: @@ -36,8 +63,13 @@ static int hvmemul_do_io( curr->arch.hvm_vcpu.io_state = HVMIO_none; if ( val == NULL ) return X86EMUL_UNHANDLEABLE; - *val = curr->arch.hvm_vcpu.io_data; - return X86EMUL_OKAY; + goto finish_access; + case HVMIO_dispatched: + /* May have to wait for previous cycle of a multi-write to complete. */ + if ( is_mmio && !value_is_ptr && (dir == IOREQ_WRITE) && + (addr == (curr->arch.hvm_vcpu.mmio_large_write_pa + + curr->arch.hvm_vcpu.mmio_large_write_bytes)) ) + return X86EMUL_RETRY; default: return X86EMUL_UNHANDLEABLE; } @@ -80,8 +112,6 @@ static int hvmemul_do_io( *reps = p->count; p->state = STATE_IORESP_READY; hvm_io_assist(); - if ( val != NULL ) - *val = curr->arch.hvm_vcpu.io_data; curr->arch.hvm_vcpu.io_state = HVMIO_none; break; case X86EMUL_UNHANDLEABLE: @@ -92,7 +122,43 @@ static int hvmemul_do_io( BUG(); } - return rc; + if ( rc != X86EMUL_OKAY ) + return rc; + + finish_access: + if ( val != NULL ) + *val = curr->arch.hvm_vcpu.io_data; + + if ( is_mmio && !value_is_ptr ) + { + /* Part of a multi-cycle read or write? */ + if ( dir == IOREQ_WRITE ) + { + paddr_t pa = curr->arch.hvm_vcpu.mmio_large_write_pa; + unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_write_bytes; + if ( bytes == 0 ) + pa = curr->arch.hvm_vcpu.mmio_large_write_pa = addr; + if ( addr == (pa + bytes) ) + curr->arch.hvm_vcpu.mmio_large_write_bytes += size; + } + else + { + paddr_t pa = curr->arch.hvm_vcpu.mmio_large_read_pa; + unsigned int bytes = curr->arch.hvm_vcpu.mmio_large_read_bytes; + if ( bytes == 0 ) + pa = curr->arch.hvm_vcpu.mmio_large_read_pa = addr; + if ( (addr == (pa + bytes)) && + ((bytes + size) < + sizeof(curr->arch.hvm_vcpu.mmio_large_read)) ) + { + memcpy(&curr->arch.hvm_vcpu.mmio_large_read[addr - pa], + val, size); + curr->arch.hvm_vcpu.mmio_large_read_bytes += size; + } + } + } + + return X86EMUL_OKAY; } static int hvmemul_do_pio( @@ -793,6 +859,11 @@ int hvm_emulate_one( hvmemul_ctxt->exn_pending = 0; rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops); + + if ( rc != X86EMUL_RETRY ) + curr->arch.hvm_vcpu.mmio_large_read_bytes = + curr->arch.hvm_vcpu.mmio_large_write_bytes = 0; + if ( rc != X86EMUL_OKAY ) return rc; diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h index 6ff8de5fc4..fc43d5d20d 100644 --- a/xen/include/asm-x86/hvm/vcpu.h +++ b/xen/include/asm-x86/hvm/vcpu.h @@ -83,10 +83,16 @@ struct hvm_vcpu { */ unsigned long mmio_gva; unsigned long mmio_gpfn; - + /* Callback into x86_emulate when emulating FPU/MMX/XMM instructions. */ void (*fpu_exception_callback)(void *, struct cpu_user_regs *); void *fpu_exception_callback_arg; + /* We may read up to m128 as a number of device-model transactions. */ + paddr_t mmio_large_read_pa; + uint8_t mmio_large_read[16]; + unsigned int mmio_large_read_bytes; + /* We may write up to m128 as a number of device-model transactions. */ + paddr_t mmio_large_write_pa; + unsigned int mmio_large_write_bytes; }; #endif /* __ASM_X86_HVM_VCPU_H__ */ -